/*******************************************************************************************
Copyright (C) 2013 Mestrelab Research S.L. All rights reserved.

This file is part of the Mnova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*******************************************************************************************/

/*globals mainWindow, nmr, serialization, settings, Application, Dir, File, FileDialog, MnUi, NMRSpectrum, ProgressDialog, Str, TextStream*/
/*jslint plusplus: true, indent: 4*/

function importLCModelAscii() {
	"use strict";

	function getLCModelAsciiParam(aParamName, aHeader) {
		var eqPos, nlPos,
			parPos = aHeader.indexOf(aParamName);
		if (parPos === -1) {
			return undefined;
		}

		eqPos = aHeader.indexOf("=", parPos);
		if (eqPos === -1) {
			return undefined;
		}

		nlPos = aHeader.indexOf("\n", eqPos);
		if (nlPos === -1) {
			nlPos = aHeader.length;
		}

		return aHeader.substring(eqPos + 1, nlPos).replace(/^[\t ]*/, "");
	}

	var fi, fileName, fin, sin, header, headerEnd, dataStr, data, specSize, frequency, step,
		i, spectrum, proc, fromPPM, endPPM, nucleus, re, realValues, im, imgValues, progressBar,
		dirSetKey = "importLCModelAscii/Dir", auxFileName, refFreq,
		openDir = settings.value(dirSetKey, Dir.home()), auxData, auxiliaryDataArray,
		fileNames = FileDialog.getOpenFileNames("LCModel ASCII (*.raw)", "", openDir);

	if (!fileNames.length) {
		return;
	}

	//Create a progress bar in order to inform to the user about the state of the import process
	progressBar = new ProgressDialog();
	progressBar.minimum = 0;
	progressBar.maximum = 100;
	progressBar.value = 0;
	progressBar.visible = true;

	serialization.fileHistory = false;
	for (fi = 0; fi < fileNames.length; fi++) {
		fileName = fileNames[fi];
		fin = new File(fileName);

		//Update progress bar
		auxFileName = fileName.substring(fileName.lastIndexOf("/") + 1, fileName.length);
		progressBar.labelText = "Importing " + auxFileName + " file";
		progressBar.value = (fi / fileNames.length) * 100;
		progressBar.update();

		if (!fi) {
			settings.setValue(dirSetKey, fin.absDirPath);
		}

		fin.open(File.ReadOnly);
		sin = new TextStream(fin);

		header = sin.readAll();

		headerEnd = header.lastIndexOf("$END\n");
		if (headerEnd === -1) {
			fin.close();
		} else {
			dataStr = header.substring(headerEnd + 6, header.length);
			dataStr = dataStr.replace(/[ \t\n\r]*$/, "");
			data = dataStr.split("\n");
			header = header.substring(0, headerEnd + 5);

			//Get needed parameters to create the spectrum. To guess ppm values we use the formula  1 / (dim1_step × synthesizer_frequency)
			specSize = Number(data.length);
			frequency = Number(getLCModelAsciiParam("hzpppm", header));
			step = Number(getLCModelAsciiParam("deltat", header));

			//If for that reason these values are missing in header block, we use the default values written at TASCIINMRConverter
			//TASCIINMRConverter looks for entry "frequency" in the header. If there is no entry (but it's - it says "frequency undefined") it sets to 400.
			//Otherwise somewhere else it set it to default 300 stored at NMR General.cpp essentials::defMHz = 300.0;
			if (frequency === "undefined" || frequency === undefined) {
				frequency = 400;
			} else if (isNaN(frequency)) {
				frequency = 300;
			}
			if (isNaN(step) || !step) {
				step = 0.0005;
			}

			//Ppm calculation by using the reference frequency
			//The ppm scale has to be calculated against reference frequency, not the spectrometer frequency.
			refFreq = frequency - 1e-6 / (2.0 * step);
			fromPPM = 0;
			endPPM = (1 / (step * refFreq));

			//Create the spectrum object
			spectrum = importLCModelAscii.createSpectrum(specSize, nucleus, frequency, fromPPM, endPPM, fileName);

			//If the spectrum is fine we fill it with data
			if (spectrum !== undefined) {

				//Get the spectrum data in time domain
				realValues = [];
				imgValues = [];
				for (i = 0; i < specSize && !progressBar.wasCanceled; i++) {
					auxData = data[i].trim();
					auxiliaryDataArray = auxData.split(/\s+/);
					re = auxiliaryDataArray[0];
					im = auxiliaryDataArray[1];
					realValues.push(re);
					imgValues.push(im);
				}
				fin.close();

				//Fill spectrum at a single shot with data
				if (realValues.length > 0 && imgValues.length > 0) {
					nmr.beginFidModification(spectrum);
					spectrum.fidSetReal("all", realValues);
					spectrum.fidSetImag("all", imgValues);
					nmr.endFidModification(spectrum);
					spectrum.update();
				}

				//Apply processing parameters in order to get the Fourier Transform
				//The last processing parameter allows to match the number of points (spectral size)
				//The serialization used by the old script performs a Phase Correction implicitly.
				//However, even though it uses a automatic regions analysis it also uses a specific algorithm to get the angles
				if (spectrum.isValid()) {
					proc = spectrum.proc;
					proc.setParameter("PC[1].Method", "Regions Analysis");
					proc.setParameter("FT[1].Invert", true);
					proc.setParameter("FT[1].Quadrature", true);
					proc.setParameter("ZF[1].size", spectrum.fidCount(1) * 2);
					spectrum.process(proc);
					spectrum.fitToHeight();
					spectrum.update();
				}
			}
		}
	}

	//Update current document
	if (Application.mainWindow.activeDocument !== undefined) {
		Application.mainWindow.activeDocument.update();
	}

	//Finalize progress bar and history
	serialization.fileHistory = true;
	progressBar.value = 100;
	progressBar.visible = false;
}

importLCModelAscii.createSpectrum = function createSpectrum(aSize, aNuc, aMhz, aPpm1, aPpm2, aFileName) {
	"use strict";

	var spectrum;

	//Create spectrum object
	spectrum = new NMRSpectrum(
		{
			1: { nucleus: aNuc, frequency: aMhz, from_ppm: aPpm1, to_ppm: aPpm2, size: aSize },
			filename: aFileName,
			origin: 'LCMoldel ASCII raw file',
			title: ''
		}
	);

	return spectrum;
};

if (this.MnUi && MnUi.scripts_nmr) {
	MnUi.scripts_nmr.scripts_nmr_ImportLCModelASCII = importLCModelAscii;
}
